#include "key_task.h"
#include "main.h"
#include "key.h"
#include "led.h"

#define LONG_BEGING_1 (0x01U)
#define LONG_BEGING_2 (0x02U)
#define LONG_BEGING_3 (0x04U)
#define LONG_BEGING_4 (0x08U)

void _LongDetect(uint8_t long_detect, uint8_t key);

/* 按键事件组 */
static uint16_t key_events = 0;
/* 长按计数 */
static uint8_t long_count[4] = {
  KEY_LONG_TIME,
  KEY_LONG_TIME,
  KEY_LONG_TIME,
  KEY_LONG_TIME
};
/* 长按检测开始，按键按下/抬起对应位分别置一/清零 */
static uint8_t long_begin = 0; 

/**
 * @brief 按键任务，间隔KEY_TASK_TICK ms执行
 */
void Key_Task(void)
{
  static uint8_t key_old     = 0;
  uint8_t key_new            = Key_GetValue();
  uint8_t events             = 0;
  
  /* 按键按下事件 */
  events       = key_new & (key_new ^ key_old);
  key_events  |= events << 0;
  long_begin  |= events;
  
  /* 按键抬起事件 */
  events       = ~key_new & (key_new ^ key_old);
  key_events  |= events << 4;
  long_begin  &= ~events;
  
  /* 按键长按事件 */
  _LongDetect(long_begin, 0);
  _LongDetect(long_begin, 1);
  _LongDetect(long_begin, 2);
  _LongDetect(long_begin, 3);
  
  key_old = key_new;
}

uint16_t Key_GetState(void)
{
  return key_events;
}

void Key_ClearState(uint16_t evnet)
{
  /*
   * 如果长按保持中，那么禁止清除长按事件位
  */
  evnet &= ~((uint16_t)long_begin << 8);
  
  key_events &= ~evnet;
}

/**
 * @brief 按键长按检测
 * @para long_detect 按键长按检测状态
 * @para key 期望检测的按键 value: 0~3
*/
void _LongDetect(uint8_t long_begin, uint8_t key)
{
  /* 
   * 如果长按开始，则计数值递减，并判断是否达到长按时长，反之保持KEY_LONG_TIME
  */
  uint8_t long_bit = 0x1U << key;
  if((long_begin & long_bit) == long_bit)
  {
    if(long_count[key] == 0)
    {
      key_events |= (uint16_t)long_bit << 8;
    }
    else
    {
      long_count[key]--;
    }
  }
  else
  {
    long_count[key] = KEY_LONG_TIME;
  }
}
